混了兩天範例,該認真點了XD
今天要訓練模型,儲存模型,讀取模型,拿模型分類圖片,
以下程式碼是昨天的範例,但在最後加上 save ,來儲存模型。
為了自己測試方便,我把檔案副檔名改成了 Jupyter Notebook 的格式(ipynb)。
# a02_tf_mnist.ipynb
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 訓練
model.fit(x_train, y_train, epochs=5)
# 用測試資料評估
model.evaluate(x_test, y_test, verbose=2)
# 將模型存在 mnist 資料夾
model.save("mnist")
資料夾格式如下,我目前的版本是tensorflow 2.6.0,
其他版本格式可能不同。
接下來再開一個新檔案,a03_tf_category.py
# a03_tf_category.ipynb
import tensorflow as tf
saved_model_path = "mnist"
# 讀取模型
model = tf.keras.models.load_model(saved_model_path)
# 顯示模型資訊
model.summary()
# 顯示模型的輸入輸出格式
print(model.input)
# KerasTensor(type_spec=TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name='flatten_input'), name='flatten_input', description="created by layer 'flatten_input'")
print(model.output)
# KerasTensor(type_spec=TensorSpec(shape=(None, 10), dtype=tf.float32, name=None), name='dense_1/Softmax:0', description="created by layer 'dense_1'")
可以從以下資訊中得知,輸入是一個三維浮點數陣列
第一個維度沒有限制長度,而二三維長度限制是 28。
shape=(None, 28, 28), dtype=tf.float32
接下來看看最初怎麼訓練的。
mnist 是手寫數字集。
mnist.load_data() 會回傳 shape == (60000, 28, 28),且數值介於 0~255 的浮點數。
也就是 60000 張 28 x 28 的手寫數字。
https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist/load_data
而在訓練前,範例將數值除以 255,變成介於 0~1 的浮點數。
x_train, x_test = x_train / 255.0, x_test / 255.0
那麼如果我們要用這個模型來分類,要做的預處理就是把圖片處理成 28x28,介於 0~1 的浮點數陣列。
安裝 opencv
conda install -c anaconda opencv
之後來處理圖片,這裡我畫了3張圖
使用 opencv ,讀取讀片,轉灰階,縮小為 28x28。
import cv2
# 讀取圖片 1
img = cv2.imread('1.png')
print(img.shape) # (100, 100, 3)
# 預設圖片讀進來是彩色,有RGB的維度,於是我在這裡把圖片轉灰階
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(imggray.shape) # (100, 100)
# 縮小為 28x28
resized = cv2.resize(imggray, (28, 28))
print(resized.shape) # (28, 28)
# mnist 的圖集黑色是255,白色是 0,而圖片讀進來是 黑色是0,白色是 255
# 所以在這裡除255後,也順便把黑白翻轉過來。
resized = 1 - resized / 255.0
# 原本的格式是將 N 張圖片丟進去訓練,,所以預測時也不能直接丟,而是在外面包一層陣列。
# 最後將陣列化 resized 轉成 tensor 進行預測。
model(tf.constant([resized]))
# <tf.Tensor: shape=(1, 10), dtype=float32, numpy=
# array([[1.1365917e-04, 9.4607556e-01, 3.3843194e-03, 9.3289698e-03,
# 3.3142285e-03, 3.7603064e-03, 1.8111777e-03, 7.1768690e-04,
# 3.1470988e-02, 2.3163184e-05]], dtype=float32)>
# 科學記號不方便看,所以在這裡改為小數點後兩位。
# mnist 的順序是從 0 開始,所以 1.png 這張題片擺在第2位。
# 輸出是一組機率陣列。
[[round(float(j), 2) for j in i] for i in model(tf.constant([resized]))]
# [[0.0, 0.95, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.03, 0.0]]
接下來一次分類三張圖吧
def readimg(imgpath):
img = cv2.imread(imgpath)
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
resized = cv2.resize(imggray, (28, 28))
return 1 - resized / 255.0
imgfiles = ["1.png", "2.png", "3.png"]
imgs = [readimg(i) for i in imgfiles]
[[round(float(j), 2) for j in i] for i in model(tf.constant(imgs))]
# [[0.0, 0.95, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.03, 0.0],
# [0.0, 0.0, 0.99, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
# [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]